<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MINIO upload</title>
    <!-- <script src="https://unpkg.com/axios/dist/axios.min.js"></script> -->
    <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>
</head>

<body>
    <h1>minio upload</h1>

    <!-- <form method="post" action="/api/upload" enctype="multipart/form-data">
        <div>
            文件: <input type="file" name="file" />
        </div>
        <div>
            <button click="doUpload()">上传12</button>
        </div>
    </form> -->
    <div>
        文件: <input type="file" name="file" />
    </div>
    <div>
        <button onclick="doUpload()">上传</button>
        <div id="response">
            <div>
                总计：<span id="total"></span>
            </div>
            <div style="width: 100%;height: 30px;background-color: red">
                <span id="bar" style="display:block;height: 30px;background-color: blue;width: 1%"></span>
            </div>
        </div>
    </div>

    <script>

        function ProgressBar(containerId, msgId, total, callback) {
            this.width = "0%"
            this.total = total
            this.cur = 0
            this.callback = callback
            this.containerObj = document.querySelector(containerId)
            this.msgObj = document.querySelector(msgId)
            this.beginTime = null
            this.endTime = null
        }

        ProgressBar.prototype.reset = function () {
            this.cur = 0
            this.width = "0%"
            this.msgObj.innerHTML = ''
            this.containerObj.style.width = this.width
        }

        ProgressBar.prototype.render = function () {
            const percent = Math.round((this.cur / this.total) * 100)
            console.log('percent', percent)
            if (!this.beginTime) {
                this.beginTime = new Date()
            }
            this.callback && this.callback.apply(null, this.cur, this.total, percent)
            if (percent > 100) {
                return
            }
            this.width = percent + "%";
            this.containerObj.style.width = this.width
            this.msgObj.innerHTML = this.width
        }

        ProgressBar.prototype.run = function (cur) {
            this.cur = cur
            this.render()
        }

        ProgressBar.prototype.increase = function () {
            if (this.cur < this.total) {
                this.cur = this.cur + 1
                this.render()
                return false
            }
            return true
        }

        ProgressBar.prototype.stop = function() {
            this.endTime = new Date()
        }

        // const total = 100
        // const bar = new ProgressBar('#bar', '#total', 100)
        // const handle = setInterval(() => {
        //     const end = bar.increase()
        //     if (end) {
        //         clearInterval(handle)
        //     }
        // }, 1000)


        let config = {
            headers: {
                'Content-Type': 'multipart/form-data;boundary = ' + new Date().getTime()
            }
        }

        const uploadUrl = "/api/upload"

        function doUpload() {
            const file = document.querySelector('input[type=file]').files[0]
            const blockSize = 1 * 1024 * 1024
            const entry = createFileEntry(file, blockSize)
            console.log('chunks', entry.chunks.length)
            const allForms = entry.chunks.filter(it => !it.isEnd).map(c => createFormData(c, entry.time))
            const endForms = entry.chunks.filter(it => it.isEnd).map(c => createFormData(c, entry.time))
            // const allForms = createFormData(entry.chunks, entry.time)


            const bar = new ProgressBar('#bar', '#total', entry.chunks.length)
            bar.reset()

            const beforePost = createPromise(uploadUrl, allForms)
                .map(p => new Promise((resolve, reject) => {
                    bar.increase()
                    p.then(resolve)
                }))
            const endPost = createPromise(uploadUrl, endForms)
                .map(p => new Promise((resolve, reject) => {
                    bar.increase()
                    setTimeout(() => {
                        p.then(resolve)
                    }, 100)
                }))

            Promise.all(beforePost).then(r => {
                console.log("分块上传完成", r)
                Promise.all(endPost).then(end => {
                    console.log('上传完成', end)
                })
            })

            // console.log(endForms)
        }

        function createPromise(uploadUrl, formDatas) {
            console.log('formDatas', formDatas)
            return formDatas.map(f => axios.post(uploadUrl, f, config))
        }

        function createFormData(chunk, time) {
            const formData = new FormData()
            formData.append('file', chunk.blob)
            formData.append('name', chunk.fileName)
            formData.append('isEnd', chunk.isEnd)
            formData.append("index", chunk.index)
            formData.append('blockName', chunk.genBlockName(time))
            formData.append('time', time)
            formData.append('name_without_ext', chunk.nameWithoutExt())
            return formData
        }

        function createFileEntry(file, blockSize) {
            console.log('file info', file)

            const chunks = []

            // var blockSize = 1 * 1024 * 1024
            var blockNum = Math.ceil(file.size / blockSize)
            console.log('blockNum', blockNum)
            for (let num = 1; num <= blockNum; num++) {
                const startSize = (num - 1) * blockSize;
                const nextSize = Math.min(num * blockSize, file.size)
                var fileData = file.slice((num - 1) * blockSize, nextSize)
                const chunk = new FileChunk(fileData, startSize, nextSize, num == blockNum, num, file.name)
                chunks.push(chunk)
            }
            return { chunks, fileName: file.name, type: file.type, size: file.size, time: new Date().getTime() }
        }

        function FileChunk(blob, startSize, nextSize, isEnd, index, fileName) {
            this.blob = blob
            this.startSize = startSize
            this.nextSize = nextSize
            this.isEnd = isEnd
            this.index = index
            this.fileName = fileName


            this.genBlockName = function (time) {
                const name = this.fileName.split('.')[0]
                return `${time}-${name}-${this.index}`
            }

            this.nameWithoutExt = function () {
                return this.fileName.split('.')[0]
            }

        }


    </script>

</body>

</html>